﻿using Digitalmes.Domain.Enums;
using Digitalmes.Scada.Configuration;
using Digitalmes.Scada.Management;
using Digitalmes.Scada.Models;
using Digitalmes.Scada.Services;

namespace Digitalmes.Scada.Handlers;

/// <summary>
/// 设备消息请求预处理，用于异步处理通知消息，如警报、设备状态信息。
/// </summary>
internal sealed class NoticeApiHandler : IDirectMessageRequestApi
{
    private readonly IServiceProvider _serviceProvider;

    private readonly IAlarmService _alarmService;
    private readonly EquipmentStateManager _equipmentStateManager;
    private readonly ILogger _logger;

    public NoticeApiHandler(IServiceProvider serviceProvider,
        IAlarmService alarmService,
        EquipmentStateManager equipmentStateManager,
        ILogger<NoticeApiHandler> logger)
    {
        _serviceProvider = serviceProvider;
        _alarmService = alarmService;
        _equipmentStateManager = equipmentStateManager;
        _logger = logger;
    }

    public async Task PostAsync(PayloadData? lastMasterPayloadData, RequestMessage requestMessage, CancellationToken cancellationToken)
    {
        try
        {
            if (requestMessage.Flag != TagFlag.Notice)
            {
                return;
            }

            var self = requestMessage.Self();
            if (self.TagName == TagDefine.PLC_Alarm)  // 设备警报
            {
                bool[]? lastAlarms = null;
                bool[] newAlarms = [];

                // 只允许为 bit 和 int16 类型
                if (self.DataType == TagDataType.Bit)
                {
                    lastAlarms = lastMasterPayloadData?.GetBitArray();
                    newAlarms = self.GetBitArray();
                }
                else if (self.DataType == TagDataType.Int)
                {
                    lastAlarms = lastMasterPayloadData?.GetIntArray().Select(s => s == 1).ToArray();
                    newAlarms = self.GetIntArray().Select(s => s == 1).ToArray();
                }

                // 若是警报来自工位，选择采用工位警报。
                string deviceName = !string.IsNullOrEmpty(requestMessage.Schema.TagGroupName)
                    ? requestMessage.Schema.TagGroupName
                    : requestMessage.Schema.DeviceName;
                await _alarmService.RecordAlarmAsync(new AlarmInput
                {
                    Line = requestMessage.Schema.ChannelName,
                    DeviceName = deviceName,
                    LastAlarms = lastAlarms,
                    NewAlarms = newAlarms,
                    IsFromTagGroup = !string.IsNullOrEmpty(requestMessage.Schema.TagGroupName),
                });
            }
            else if (self.TagName == TagDefine.PLC_Equipment_State) // 设备运行状态
            {
                int state = self.GetInt(); // 转换可能异常
                if (Enum.IsDefined(typeof(EquipRunningState), state))
                {
                    await _equipmentStateManager.ChangeStateAsync(GetEquipmentCodeInput(), (EquipRunningState)state, cancellationToken);
                }
            }
            else if (self.TagName == TagDefine.PLC_Equipment_Mode)  // 设备运行模式
            {
                int mode = self.GetInt();
                if (Enum.IsDefined(typeof(EquipRunningMode), mode))
                {
                    await _equipmentStateManager.ChangeModeAsync(GetEquipmentCodeInput(), (EquipRunningMode)mode, cancellationToken);
                }
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "[{NoticeApiHandler}] 请求数据预处理异常。", nameof(NoticeApiHandler));
        }

        EquipmentCodeInput GetEquipmentCodeInput()
        {
            EquipmentCodeInput input = new()
            {
                Line = requestMessage.Schema.ChannelName,
                EquipmentCodes = [],
            };

            // 标记归属于分组
            if (!string.IsNullOrEmpty(requestMessage.Schema.TagGroupName))
            {
                input.EquipmentCodes.Add(requestMessage.Schema.TagGroupName);
                return input;
            }

            // 标记归属于设备，查找设备下所有分组
            var deviceFactory = _serviceProvider.GetRequiredService<IDeviceFactory>();
            var device = deviceFactory.GetDevice(requestMessage.Schema.ChannelName, requestMessage.Schema.DeviceName);
            if (device != null)
            {
                input.EquipmentCodes.AddRange(device.TagGroups.Select(s => s.Name));
                return input;
            }

            // 若设备下没有分组，直接用设备名称。
            input.EquipmentCodes.Add(requestMessage.Schema.DeviceName);

            return input;
        }
    }
}
